home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 August: Tool Chest / Dev.CD Aug 98 TC.toast / What's New? / Software Development Kits / Mac OS USB DDK / MacOS USB DDK 1.0b4 / NeptuneDDK / Examples / MouseModule / MouseModule.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-26  |  11.5 KB  |  361 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        MouseModule.c
  3.  
  4.     Contains:    HID Module for USB Mouse
  5.  
  6.     Version:    xxx put version here xxx
  7.  
  8.     Copyright:    © 1997-1998 by Apple Computer, Inc., all rights reserved.
  9.  
  10. */
  11.  
  12. #include <Types.h>
  13. #include <Devices.h>
  14. #include <processes.h>
  15. #include <DriverServices.h>
  16. #include <USB.h>
  17.  
  18. #include "MouseModule.h"
  19.  
  20. usbMousePBStruct myMousePB;
  21.  
  22. void InitParamBlock(USBDeviceRef theDeviceRef, USBPB * paramblock)
  23. {
  24.     paramblock->usbReference = theDeviceRef;
  25.     paramblock->pbVersion = kUSBCurrentPBVersion;
  26.     paramblock->usbWIndex = 0;             
  27.     paramblock->usbBuffer = nil;        
  28.     paramblock->usbStatus = noErr;
  29.     paramblock->usbReqCount = 0;
  30.     paramblock->usbWValue = 0;
  31.     paramblock->usbFlags = 0;
  32. }
  33.  
  34.  
  35.  
  36. Boolean immediateError(OSStatus err)
  37. {
  38.     return((err != kUSBPending) && (err != noErr) );
  39. }
  40.  
  41. void MouseModuleInitiateTransaction(USBPB *pb)
  42. {
  43. register usbMousePBStruct *pMousePB;
  44. OSStatus myErr;
  45.  
  46.     pMousePB = (usbMousePBStruct *)(pb);
  47.     pMousePB->transDepth++;
  48.     if (pMousePB->transDepth < 0)
  49.     {
  50.         USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: transDepth < 0 (initiation)", pMousePB->transDepth );
  51.     }
  52.     
  53.     if (pMousePB->transDepth > 1)
  54.     {
  55.         USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: transDepth > 1 (initiation)", pMousePB->transDepth );
  56.     }
  57.     
  58.     switch(pMousePB->pb.usbRefcon & ~kRetryTransaction)
  59.     {
  60.         case kGetFullConfiguration:
  61.             InitParamBlock(pMousePB->deviceRef, &pMousePB->pb);
  62.             
  63.             pMousePB->pb.usbRefcon |= kCompletionPending;
  64.             pMousePB->pb.usbCompletion = (USBCompletion)TransactionCompletionProc;
  65.             myErr = USBGetFullConfigurationDescriptor(pb);
  66.             if(immediateError(myErr))
  67.             {
  68.                 USBExpertFatalError(pMousePB->pb.usbReference, kUSBInternalErr, "\pUSBHIDMouseModule: kGetFullConfiguration (ImmediateError)", myErr);
  69.             }
  70.             break;
  71.             
  72.         case kFindInterfaceAndSetProtocol:
  73.             myErr = FindHIDInterfaceByProtocol(pMousePB->pFullConfigDescriptor, kHIDMouseInterfaceProtocol, &pMousePB->pInterfaceDescriptor );    // find the HID interface
  74.             if ((pMousePB->pInterfaceDescriptor == NULL) || (myErr != noErr))
  75.             {
  76.                 USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: Interface not found", myErr);
  77.                 pMousePB->pb.usbRefcon = kReturnFromDriver;
  78.             }
  79.             
  80.             InitParamBlock(pMousePB->deviceRef, &pMousePB->pb);
  81.             
  82.             pMousePB->pb.usbBMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  83.             pMousePB->pb.usbBRequest = kHIDRqSetProtocol;
  84.             pMousePB->pb.usbWValue = kHIDBootProtocolValue; 
  85.             pMousePB->pb.usbWIndex = pMousePB->pInterfaceDescriptor->interfaceNumber;
  86.             pMousePB->pb.usbCompletion = (USBCompletion)TransactionCompletionProc;
  87.             
  88.             pMousePB->pb.usbRefcon |= kCompletionPending;
  89.             myErr = USBDeviceRequest(&pMousePB->pb);
  90.             if (immediateError(myErr))
  91.             {
  92.                 USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: kSetProtocol (ImmediateError)", myErr);
  93.             }
  94.             break;
  95.             
  96.         case kSetIdleRequest:
  97.             InitParamBlock(pMousePB->deviceRef, &pMousePB->pb);
  98.             
  99.             pMousePB->pb.usbBMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  100.             
  101.             pMousePB->pb.usbBRequest = kHIDRqSetIdle;
  102.             if ((myMousePB.deviceDescriptor.vendor == USB_CONSTANT16(0x1452)) &&
  103.                 (myMousePB.deviceDescriptor.product == USB_CONSTANT16(0x0301)) &&
  104.                 (pMousePB->deviceDescriptor.devRel == USB_CONSTANT16(0x0004)))
  105.             {
  106.                 pMousePB->pb.usbWValue = ((50/4)<<8);                 // force a read completion if idle for more than 50ms
  107.             }
  108.             else
  109.             {
  110.                 pMousePB->pb.usbWValue = 0;                         // Turn off SetIdle time (set it to 0ms)
  111.             }
  112.             pMousePB->pb.usbWIndex = pMousePB->interfaceDescriptor.interfaceNumber;
  113.             pMousePB->pb.usbCompletion = (USBCompletion)TransactionCompletionProc;
  114.             
  115.             pMousePB->pb.usbRefcon |= kCompletionPending;
  116.  
  117.             myErr = USBDeviceRequest(&pMousePB->pb);
  118.             if(immediateError(myErr))
  119.             {
  120.                 USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: kSetIdleRequest - immediate error", myErr);
  121.             }
  122.             break;
  123.  
  124.         case kFindAndOpenInterruptPipe:
  125.             pMousePB->pb.usbClassType = kUSBInterrupt;
  126.             pMousePB->pb.usbOther = 0;            
  127.             pMousePB->pb.usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
  128.             pMousePB->pb.usbFlags = kUSBIn;
  129.             pMousePB->pb.usbBuffer = pMousePB->pInterfaceDescriptor;
  130.             pMousePB->pb.usbReqCount = (UInt8*)pMousePB->pInterfaceDescriptor - (UInt8*)pMousePB->pFullConfigDescriptor;
  131.             myErr = USBFindNextEndpointDescriptor( &pMousePB->pb );
  132.             if((immediateError(myErr)) || (pMousePB->pb.usbBuffer == nil))
  133.             {
  134.                 USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: Endpoint not found", myErr);
  135.                 pMousePB->pb.usbRefcon = kReturnFromDriver;
  136.             }
  137.             else
  138.             {
  139.                 pMousePB->pEndpointDescriptor = (USBEndPointDescriptorPtr) pMousePB->pb.usbBuffer;
  140.  
  141.                 InitParamBlock(pMousePB->deviceRef, &pMousePB->pb);
  142.                 
  143.                 pMousePB->pb.usbFlags = kUSBIn;
  144.                 pMousePB->pb.usbWValue = USBToHostWord(pMousePB->pEndpointDescriptor->maxPacketSize);
  145.                 pMousePB->pb.usbClassType = kUSBInterrupt;
  146.                 pMousePB->pb.usbOther = (pMousePB->pEndpointDescriptor->endpointAddress & 0x0f);
  147.                 pMousePB->pb.usbRefcon |= kCompletionPending;
  148.                 pMousePB->pb.usbCompletion = (USBCompletion)TransactionCompletionProc;
  149.         
  150.                 myErr = USBOpenPipe( &pMousePB->pb );
  151.                 if(immediateError(myErr))
  152.                 {
  153.                     USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: USBOpenPipe Failed (ImmediateError)", myErr);
  154.                 }
  155.             }
  156.             break;
  157.         
  158.         case kReadInterruptPipe:
  159.             InitParamBlock(pMousePB->pipeRef, &pMousePB->pb);
  160.  
  161.             pMousePB->pb.usbBuffer = (Ptr)pMousePB->hidReport;
  162.             pMousePB->pb.usbReqCount = USBToHostWord(pMousePB->pEndpointDescriptor->maxPacketSize);
  163.             pMousePB->pb.usbWIndex = pMousePB->interfaceDescriptor.interfaceNumber;    
  164.             pMousePB->pb.usbCompletion = (USBCompletion)TransactionCompletionProc;
  165.             
  166.             pMousePB->pb.usbRefcon |= kCompletionPending;
  167.         
  168.             myErr = USBIntRead(&pMousePB->pb);
  169.             if(immediateError(myErr))
  170.             {
  171.                 USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: Read Interrupt Pipe (ImmediateError)", myErr);
  172.             }
  173.             break;
  174.             
  175.         default:
  176.             USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: Transaction initiated with bad refcon value", pMousePB->pb.usbRefcon);
  177.             pMousePB->pb.usbRefcon = kUndefined + kReturnFromDriver;
  178.             break;
  179.     }
  180.     
  181. // At this point the control is returned to the system.  If a USB transaction
  182. // has been initiated, then it will call the Complete procs
  183. // (below) to handle the results of the transaction.
  184. }
  185.  
  186.  
  187. void TransactionCompletionProc(USBPB *pb)
  188. {
  189. register usbMousePBStruct *pMousePB;
  190. unsigned char    * errstring;
  191.  
  192.     pMousePB = (usbMousePBStruct *)(pb);
  193.     pMousePB->transDepth--;
  194.     if (pMousePB->transDepth < 0)
  195.     {
  196.         USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: transDepth < 0 (completion)", pMousePB->transDepth );
  197.     }
  198.     
  199.     if (pMousePB->transDepth > 1)
  200.     {
  201.         USBExpertFatalError(pMousePB->deviceRef, kUSBInternalErr, "\pUSBHIDMouseModule: transDepth > 1 (completion)", pMousePB->transDepth );
  202.     }
  203.     
  204.     if((pMousePB->pb.usbStatus != noErr) && (pMousePB->pb.usbStatus != kUSBPending))
  205.     {
  206.         USBExpertFatalError(pMousePB->deviceRef, pMousePB->pb.usbStatus, "\pUSBHIDMouseModule: USL Reported an error", pMousePB->deviceRef);
  207.         if (pMousePB->pipeRef)
  208.         {
  209.             USBExpertStatus(pMousePB->deviceRef, "\pUSBHIDMouseModule: Attempting to clear the pipe stall", pMousePB->deviceRef);
  210.             USBClearPipeStallByReference(pMousePB->pipeRef);
  211.         }
  212.         
  213.         pMousePB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
  214.         pMousePB->pb.usbRefcon |= kRetryTransaction;
  215.         pMousePB->retryCount--;
  216.         
  217.         if (!pMousePB->retryCount)
  218.         {
  219.             switch(pMousePB->pb.usbRefcon & 0x0fff)
  220.             {
  221.                 case kGetFullConfiguration:     
  222.                     errstring = "\pUSBHIDMouseModule: kGetFullConfiguration retry failed"; break;
  223.                     
  224.                 case kFindInterfaceAndSetProtocol:     
  225.                     errstring = "\pUSBHIDMouseModule: kFindInterfaceAndSetProtocol retry failed"; break;
  226.                     
  227.                 case kFindAndOpenInterruptPipe:     
  228.                     errstring = "\pUSBHIDMouseModule: kFindAndOpenInterruptPipe retry failed"; break;
  229.                     
  230.                 case kReadInterruptPipe:     
  231.                     errstring = "\pUSBHIDMouseModule: kReadInterruptPipe retry failed"; break;
  232.                     
  233.                 default:     
  234.                     errstring = "\pUSBHIDMouseModule: retry failed (unknown state)"; break;
  235.             };
  236.             USBExpertFatalError(pMousePB->deviceRef, pMousePB->pb.usbStatus, errstring, pMousePB->deviceRef);
  237.             pMousePB->pb.usbRefcon = kReturnFromDriver;
  238.             return;
  239.         }
  240.  
  241.  
  242. // If we've tried 5 times to do a set idle, and failed 5 times, then just give up and go
  243. // open the pipe...
  244.         if ((pMousePB->retryCount == 5) && ((pMousePB->pb.usbRefcon&pMousePB->pb.usbRefcon & 0x0fff) == kSetIdleRequest))
  245.         {
  246.             pMousePB->pb.usbRefcon &= ~kRetryTransaction;
  247.             pMousePB->pb.usbRefcon = kFindAndOpenInterruptPipe;
  248.             pMousePB->pb.usbStatus = noErr;
  249.         }
  250.     }
  251.     else
  252.     {
  253.         pMousePB->pb.usbRefcon &= ~kRetryTransaction;
  254.         pMousePB->retryCount = kMouseRetryCount;
  255.     }
  256.  
  257.     if (pMousePB->pb.usbRefcon & kCompletionPending)             
  258.     {                                                
  259.         pMousePB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
  260.         switch(pMousePB->pb.usbRefcon)
  261.         {
  262.             case kGetFullConfiguration:
  263.                 pMousePB->pFullConfigDescriptor = pMousePB->pb.usbBuffer;
  264.                 if (pMousePB->pFullConfigDescriptor == nil)
  265.                 {
  266.                     USBExpertFatalError(pMousePB->pb.usbReference, kUSBInternalErr, "\pUSBHIDMouseModule: USBGetFullConfiguration - pointer is nil", pMousePB->pb.usbRefcon);
  267.                     pMousePB->pb.usbRefcon = kReturnFromDriver;
  268.                 }
  269.                 else
  270.                 {
  271.                     pMousePB->pb.usbRefcon = kFindInterfaceAndSetProtocol;
  272.                 }
  273.                 break;
  274.                 
  275.             case kFindInterfaceAndSetProtocol:
  276.                 pMousePB->pb.usbRefcon = kSetIdleRequest;
  277.                 break;
  278.                 
  279.             case kSetIdleRequest:
  280.                 pMousePB->pb.usbRefcon = kFindAndOpenInterruptPipe;
  281.                 break;
  282.                 
  283.             case kFindAndOpenInterruptPipe:
  284.                 pMousePB->pipeRef = pMousePB->pb.usbReference;
  285.                 pMousePB->pb.usbRefcon = kReadInterruptPipe;
  286.                 break;
  287.                 
  288.             case kReadInterruptPipe:
  289.                 NotifyRegisteredHIDUser(pMousePB->hidDeviceType, pMousePB->hidReport);
  290.                 pMousePB->pb.usbRefcon = kReadInterruptPipe;
  291.                 break;
  292.  
  293.         }
  294.     }
  295.     if (!(pMousePB->pb.usbRefcon & kReturnFromDriver))
  296.         MouseModuleInitiateTransaction(pb);
  297. }
  298.  
  299.  
  300. void DriverEntry(USBDeviceRef device, USBDeviceDescriptorPtr pDeviceDescriptor)
  301. {
  302. #pragma unused (device)
  303. #pragma unused (pDeviceDescriptor)
  304.  
  305. static Boolean beenThereDoneThat = false;
  306.  
  307.     return;
  308. }
  309.  
  310. void InterfaceEntry(UInt32 interfacenum, USBInterfaceDescriptorPtr pInterfaceDescriptor, USBDeviceDescriptorPtr pDeviceDescriptor, USBDeviceRef device)
  311. {
  312. #pragma unused (interfacenum)
  313.  
  314. static Boolean beenThereDoneThat = false;
  315.  
  316.     if(beenThereDoneThat)
  317.     {
  318.         USBExpertFatalError(device, kUSBInternalErr, "\pUSBHIDMouseModule is not reentrant", 0);
  319.         return;
  320.     }
  321.     beenThereDoneThat = true;
  322.     
  323. //    DebugStr("\pIn Mouse Interface Entry routine");
  324.     myMousePB.pCursorDeviceInfo = 0;                
  325.  
  326.     myMousePB.deviceDescriptor = *pDeviceDescriptor;                
  327.     myMousePB.interfaceDescriptor = *pInterfaceDescriptor;                
  328.     myMousePB.transDepth = 0;                            
  329.     myMousePB.retryCount = kMouseRetryCount;
  330.       
  331.     myMousePB.pSHIMInterruptRoutine = nil;
  332.     myMousePB.pSavedInterruptRoutine = nil;
  333.  
  334.     myMousePB.deviceRef = device;        
  335.     myMousePB.interfaceRef = nil;        
  336.     myMousePB.pipeRef = nil;        
  337.     
  338.     InitParamBlock(device, &myMousePB.pb);
  339.     
  340.     myMousePB.pb.usbReference = device;
  341.     myMousePB.pb.pbLength = sizeof(usbMousePBStruct);
  342.     myMousePB.pb.usbRefcon = kGetFullConfiguration;        
  343.     
  344.     USBHIDControlDevice(kHIDEnableDemoMode,0);
  345.  
  346.     if ((myMousePB.deviceDescriptor.vendor == USB_CONSTANT16(0x046e)) &&
  347.         (myMousePB.deviceDescriptor.product == USB_CONSTANT16(0x6782)))
  348.     {
  349.         myMousePB.unitsPerInch = (Fixed)(100<<16);
  350.     }
  351.     else
  352.     {
  353.         myMousePB.unitsPerInch = (Fixed)(400<<16);
  354.     }
  355.  
  356.     MouseModuleInitiateTransaction(&myMousePB.pb);
  357. }
  358.  
  359.  
  360.  
  361.